package com.benshou.bcss.common.j17common;

import com.benshou.bcss.common.j17common.annotation.NotNull;
import lombok.AllArgsConstructor;
import lombok.NonNull;

import java.util.Arrays;
import java.util.function.BiPredicate;
import java.util.function.Function;

/**
 * @author <a href="mailto:wh1zper@qq.com">wh1zper</a>
 */
@AllArgsConstructor
public class EqualsAndHashCodeWrapper<T> {

    public final T object;

    @NonNull
    private final BiPredicate<? super T, Object> equalsPredicate;

    @NonNull
    private final Function<? super T, @NotNull Integer> hashCodeMapper;

    public static <T> EqualsAndHashCodeWrapper<T> byAddr(T object) {
        return new EqualsAndHashCodeWrapper<>(
                object,
                (obj, other) -> obj == other,
                System::identityHashCode);
    }

    public static <T> EqualsAndHashCodeWrapper<T[]> byDeepEquals(T[] array) {
        return new EqualsAndHashCodeWrapper<>(
                array,
                (arr, other) -> {
                    if (arr == other) {
                        return true;
                    }

                    if (other == null || !other.getClass().isArray()) {
                        return false;
                    }

                    return Arrays.deepEquals(arr, (Object[]) other);},
                Arrays::deepHashCode);
    }

    @Override
    public int hashCode() {
        return this.hashCodeMapper.apply(this.object);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof EqualsAndHashCodeWrapper<?> other)) {
            return false;
        }

        return this.equalsPredicate.test(this.object, other.object);
    }
}
